/*The MIT License (MIT)

Copyright (c) <2013> <Keven "Varonth" Schulz>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

package jGW2API;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
import org.json.*;

public class jGW2API {    
    /**
     * This string is the standard URL used in all calls to the GW2 API.
     */
    public static final String Standard_URL = "https://api.guildwars2.com";
    /**
     * This is the GW2 API version used in the API calls
     */
    public static String API_Version = "/v1/";
    
    private static SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
    
    /*
     * Member fields
     */
    
    private HttpsURLConnection httpsConnection;
    
    /*
     * Constructors
     */
    /**
     * Contructs a new jGW2API object, which will use a SocketFactory generated by StartComSSLSocketFactory for SSLSockets
     * @param url The url the HttpsURLConnection should connect to
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    public jGW2API(URL url) throws IOException {
        this.httpsConnection = (HttpsURLConnection) url.openConnection();
        this.httpsConnection.setSSLSocketFactory(jGW2API.socketFactory);
    }
    
    /*
     * Methods
     */
    
    /**
     * This method is used to return a JSONObject read in from the HttpsURLConnection.
     * @return The JSONObject that was retrieved via HttpsURLConnection
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    public JSONObject getJSONObject() throws IOException {      
        BufferedReader buf = new BufferedReader(new InputStreamReader(this.httpsConnection.getInputStream()));
        String jsonString = "";
        String read;
        while ((read = buf.readLine()) != null) {
            jsonString += read;
        }
        return new JSONObject(jsonString);        
    }
    
    /**
     * Can be used for direct access to the HTTP data
     * @return the HttpsURLConnection used by this jGW2API object
     */
    public HttpsURLConnection getHttpsURLConnection() {
        return this.httpsConnection;
    }
    
    /**
     * This method is used to return a JSONArray read in from the HttpsURLConnection.
     * @return The JSONArray that was retrieved via HttpsURLConnection
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    public JSONArray getJSONArray() throws IOException {          
        BufferedReader buf = new BufferedReader(new InputStreamReader(this.httpsConnection.getInputStream()));
        String jsonString = "";
        String read;
        while ((read = buf.readLine()) != null) {
            jsonString += read;
        }
        return new JSONArray(jsonString);
    }
    
    /*
     * Static methods
     */
    
    /**
     * Static method to retrieve informations from items.json API
     * @return The JSONObject retrieved from the items.json API
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    static public JSONObject getItems() throws IOException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"items.json")).getJSONObject();
    }
    
    /**
     * Static method to retrieve informations from item_details.json for the english language
     * @param id The item ID as String that you want to request data for
     * @return The JSONObject retrieved from the item_details.json for the specific id
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if the id parameter malformed the generated URL
     */    
    static public JSONObject getItemDetails(String id) throws IOException, MalformedURLException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"item_details.json?item_id="+id)).getJSONObject();
    }
    
    /**
     * Static method to retrieve informations from item_details.json for a specific language
     * @param id The item ID as String that you want to request data for
     * @param lang The language of the item details
     * @return The JSONObject retrieved from the item_details.json for the specific id and language
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if the id or lang parameter malformed the generated URL
     */
    static public JSONObject getItemDetails(String id, String lang) throws IOException, MalformedURLException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"item_details.json?item_id="+id+"&lang="+lang)).getJSONObject();
    }
    
    /**
     * Static method to retrieve informations from recipes.json
     * @return The JSONObject retrieved from the recipes.json
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    static public JSONObject getRecipes() throws IOException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"recipes.json")).getJSONObject();
    }
    
    /**
     * Static method to retrieve informations from recipe_details.json
     * @param id The recipe ID as String that you want to request data for
     * @return The JSONObject retrieved from the recipe_details.json for the specific id
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if the id parameter malformed the generated URL
     */
    static public JSONObject getRecipeDetails(String id) throws IOException, MalformedURLException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"recipe_details.json?recipe_id="+id)).getJSONObject();
    }
    
    /**
     * Static method to retrieve informations from recipe_details.json
     * @param id The recipe ID as String that you want to request data for
     * @param lang The language of the recipe details
     * @return The JSONObject retrieved from the recipe_details.json for the specific id and language
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if the id or lang parameter malformed the generated URL
     */
    static public JSONObject getRecipeDetails(String id, String lang) throws IOException, MalformedURLException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"recipe_details.json?recipe_id="+id+"&lang="+lang)).getJSONObject();
    }
    
    /**
     * Static method to retrieve informations from wvw/matches.json
     * @return The JSONObject retrieved from the wvw/matches.json
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    static public JSONObject getWvWMatches() throws IOException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"wvw/matches.json")).getJSONObject();
    }
    
    /**
     * Static method to retrieve informations from wvw/match_details.json
     * @param id The match ID as string that you want to request data for
     * @return The JSONObject retrieved from the wvw/match_details.json for the specific id
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if the id parameter malformed the generated URL
     */
    static public JSONObject getWvWMatchDetails(String id) throws IOException, MalformedURLException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"wvw/match_details.json?match_id="+id)).getJSONObject();
    }
    
    /**
     * Static method to retrieve informations from wvw/objective_names.json
     * @return The JSONArray retrieved from wvw/objective_names.json
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    static public JSONArray getWvWObjectiveNames() throws IOException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"wvw/objective_names.json")).getJSONArray();
    }
    
    /**
     * Static method to retrieve informations from wvw/objective_names.json
     * @param lang The language of the objective names
     * @return The JSONArray retrieved from wvw/objective_names.json for the specific language 
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if the lang parameter malformed the generated URL
     */
    static public JSONArray getWvWObjectiveNames(String lang) throws IOException, MalformedURLException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"wvw/objective_names.json?lang="+lang)).getJSONArray();
    }
    
    /**
     * Static method to retrieve informations from events.json
     * @param w_id world_id parameter. Can be null to search on all worlds
     * @param e_id event_id parameter. Can be null to search for all events
     * @param m_id map_id parameter. Can be null to search on all maps
     * @return The JSONObject retrieved from events.json
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if one of the id parameters malformed the generated URL
     */
    static public JSONObject getEvents(String w_id, String e_id, String m_id) 
     throws IOException, MalformedURLException {
        String args = "";
        if (w_id != null) {
            args += "?world_id="+w_id;
        }
        if (w_id != null && e_id != null) {
            args += "&event_id="+e_id;
        }
        else if (e_id != null) {
            args += "?event_id="+e_id;
        }
        if (w_id != null && e_id != null && m_id != null 
                || w_id != null && e_id == null && m_id != null
                || w_id == null && e_id != null && m_id != null ) {
            args += "&map_id="+m_id;
        }
        else if (w_id == null && e_id == null && m_id != null) {
            args += "?m_id="+m_id;
        }
        return new jGW2API(new URL(jGW2API.Standard_URL + jGW2API.API_Version+"events.json"+args)).getJSONObject();
    }
    
    /**
     * Static method to retrieve information from event_names.json
     * @return The JSONArray retrieved from event_names.json 
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    static public JSONArray getEventNames() throws IOException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"event_names.json")).getJSONArray();
    }
    
    /**
     * Static method to retrieve information from world_names.json
     * @return The JSONArray retrieved from world_names.json
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    static public JSONArray getWorldNames() throws IOException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"world_names.json")).getJSONArray();
    }
    
    /**
     * Static method to retrieve information from map_names.json
     * @return The JSONArray retrieved from map_names.json
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    static public JSONArray getMapNames() throws IOException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"map_names.json")).getJSONArray();
    }
    
    /**
     * Static method to retrieve information from colors.json
     * @return The JSONObject retrieved from colors.json
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    static public JSONObject getColors() throws IOException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"colors.json")).getJSONObject();
    }
    
    /**
     * Static method to retrieve informations from build.json
     * @return The JSONObject retrieved from build.json
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     */
    static public JSONObject getBuildInformations() throws IOException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"build.json")).getJSONObject();
    }
    
    /**
     * Static method to retrieve informations from guild_details.json. While both parameters can be null, you will retrieve an error JSONObject if done so. You will also retrieve an error JSONObject
     * if the guild was not found. You can easily check for the error object by calling public boolean JSONObject.hasKey("error") before parsing the actual guild data.
     * @param guildID guild_id parameter. Can be null.
     * @param guildName guild_name parameter. Can be null.
     * @return The JSONObject retrieved from guild_details.json . Check for public boolean JSONObject.hasKey("error") to see if the guild was found or not.
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if one of the parameters malformed the generated URL
     */
    static public JSONObject getGuildDetails(String guildID, String guildName) throws IOException, MalformedURLException {
        String args = "";
        if (guildID != null && guildName == null) {
            args += "?guild_id="+guildID;
        }
        else if (guildID == null && guildName != null) {
            args += "?guild_name="+guildName;
        }
        else {
            args += "?guild_id="+guildID+"&guild_name="+guildName;
        }        
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"guild_details.json"+args)).getJSONObject();
    }
    
    /**
     * Static method to retrieve information from event_names.json
     * @param lang The language of the events names
     * @return The JSONArray retrieved from event_names.json for the specific language
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if the lang parameter malformed the generated URL
     */
    static public JSONArray getEventNames(String lang) throws IOException, MalformedURLException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"event_names.json?lang="+lang)).getJSONArray();
    }
    
    /**
     * Static method to retrieve informations from world_names.json
     * @param lang The language of the world names
     * @return The JSONArray retrieved from world_names.json for the specific language
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if the lang parameter malformed the generated URL
     */
    static public JSONArray getWorldNames(String lang) throws IOException, MalformedURLException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"world_names.json?lang="+lang)).getJSONArray();
    }
    
    /**
     * Static method to retrieve informations from map_names.json
     * @param lang The language of the map names
     * @return The JSONArray retrieved from map_names.json for the specific language
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if the lang parameter malformed the generated URL
     */
    static public JSONArray getMapNames(String lang) throws IOException, MalformedURLException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"map_names.json?lang="+lang)).getJSONArray();
    }
    
    /**
     * Static method to retrieve informations from colors.json
     * @param lang The language of the color names
     * @return The JSONObject retrieved from colors.json for the specific language
     * @throws IOException Thrown if the HttpsURLConnection times out, is not responding etc.
     * @throws MalformedURLException Thrown if the lang parameter malformed the generated URL
     */
    static public JSONObject getColors(String lang) throws IOException, MalformedURLException {
        return new jGW2API(new URL(jGW2API.Standard_URL+jGW2API.API_Version+"colors.json?lang="+lang)).getJSONObject();
    }
    
}
